home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / swags_z.zip / SORTING.SWG / 0035_QSort Methods.pas < prev    next >
Pascal/Delphi Source File  |  1993-08-27  |  11KB  |  368 lines

  1. {
  2. ALEXANDER CHRISTOV
  3.  
  4.  I don't know if code like this has been posted on this echo, but anyway here
  5. it goes. It implements three different versions of Qsort which so far if the
  6. fastest sorting algorithm known. However, it is not adequate For sorting File
  7. Records. I've tested the routines and have worked With them For quite a While,
  8. but don't trust me 8-) Murphy never sleeps 8-)
  9. }
  10.  
  11. Unit SORT;
  12. {─────────────────────────────────────────────────────────────────────────}
  13. { Purpose  : Unit that implements a generic QSort(), similar to           }
  14. {            the one in the standard C library.                           }
  15. { Author   : Alexander Christov                                           }
  16. { Notes    : Very instructive on the use of Pointers in TP.               }
  17. {                                                                         }
  18. {  Use freely.                                                            }
  19. {                                                                         }
  20. {─────────────────────────────────────────────────────────────────────────}
  21. Interface
  22.  
  23. Type CmpFunc=Function(El1,El2:Pointer):Boolean;
  24.  
  25. Procedure QSort(Base:Pointer;Elements,Size:Word;GT:CmpFunc);
  26.  
  27. { Base      - Pointer to the first element
  28.   Elements  - Number of elements
  29.   Size      - Size of an element in Bytes. Use SizeOf() if in doubt
  30.   GT        - A Function of Type CmpFunc that compares the elements pointed
  31.               to by the first and the second arguments and returns True
  32.               if the first is greater than the second. GT = Greater Than
  33.               8-)
  34. }
  35.  
  36. { Some commonly used CmpFunc }
  37.  
  38. Function bGT(El1,El2:Pointer):Boolean;      { Compares ^Byte }
  39. Function wGT(El1,El2:Pointer):Boolean;      { Compares ^Word }
  40. Function lGT(El1,El2:Pointer):Boolean;      { Compares ^LongInt }
  41. Function rGT(El1,El2:Pointer):Boolean;      { Compares ^Real }
  42.  
  43. Implementation
  44. {$F+}
  45.  
  46. Type Dummy=Array[0..0] of Byte;
  47.      pDummy=^Dummy;
  48.  
  49.  
  50. { Recursive Implementation }
  51.  
  52. Procedure _Sort(Base:Pointer;L,R,Size:Word;GT:CmpFunc);
  53. Var I,J:Integer;
  54. Var X:Pointer;
  55.  Procedure SwapElements(El1,El2:Word);
  56.  Var Tmp:Pointer;
  57.  begin
  58.   GetMem(Tmp,Size);
  59.   Move(pDummy(Base)^[El1*Size],Tmp^,Size);
  60.   Move(pDummy(Base)^[El2*Size],pDummy(Base)^[El1*Size],Size);
  61.   Move(Tmp^,pDummy(Base)^[El2*Size],Size);
  62.   FreeMem(Tmp,Size);
  63.  end;
  64. begin
  65.  I:=L;
  66.  J:=R;
  67.  GetMem(X,Size);
  68.  Move(pDummy(Base)^[((L+R) div 2)*Size],X^,Size);
  69.  Repeat
  70.   While GT(X,@pDummy(Base)^[I*Size]) do INC(I);
  71.   While GT(@pDummy(Base)^[J*Size],X) do DEC(J);
  72.   if I<=J then begin
  73.    if I<>J then SwapElements(I,J);
  74.    INC(I);
  75.    DEC(J);
  76.   end;
  77.  Until I>J;
  78.  FreeMem(X,Size);
  79.  if L<J then _Sort(Base,L,J,Size,GT);
  80.  if I<R then _Sort(Base,I,R,Size,GT);
  81. end;
  82.  
  83. Procedure QSort(Base:Pointer;Elements,Size:Word;GT:CmpFunc);
  84. begin
  85.  _Sort(Base,0,Elements-1,Size,GT);
  86. end;
  87.  
  88. Function bGT(El1,El2:Pointer):Boolean;
  89. Type pByte=^Byte;
  90. begin
  91.  bGt:=(pByte(El1)^>pByte(El2)^);
  92. end;
  93.  
  94. Function wGT(El1,El2:Pointer):Boolean;
  95. Type pWord=^Word;
  96. begin
  97.  wGt:=(pWord(El1)^>pWord(El2)^);
  98. end;
  99.  
  100. Function lGT(El1,El2:Pointer):Boolean;
  101. Type pLongInt=^LongInt;
  102. begin
  103.  lGt:=(pLongInt(El1)^>pLongInt(El2)^);
  104. end;
  105.  
  106. Function rGT(El1,El2:Pointer):Boolean;
  107. Type pReal=^Real;
  108. begin
  109.  rGt:=(pReal(El1)^>pReal(El2)^);
  110. end;
  111.  
  112. end.
  113.  
  114.  
  115.  
  116. {$A-,B-,D+,E-,F+,G+,I-,L+,N-,O+,P+,Q-,R-,S-,T-,V-,X+,Y+}
  117. { I don't know which settings are Really necessary For this Unit, but since
  118.   I always work With the above, I'm including them to make sure the Unit
  119.   compiles in your computer. The only critical ones (I Think) are R- and F+
  120. }
  121. Unit SORT;
  122. {─────────────────────────────────────────────────────────────────────────}
  123. { Purpose:   Unit that implements a generic QSort, similar to the         }
  124. {            one in the standard C library, but a lot more general        }
  125. {            This new version allows ordering of almost anything,         }
  126. {            even structures whose elements are not contiguous in memory  }
  127. {            or have strange mutual dependancies that don't allow "happy  }
  128. {            swapping". Obviously, this version is slower than the        }
  129. {            previous one. if you won't be sorting Linked Lists or        }
  130. {            Collections, use the previous one.                           }
  131. { Author   : Alexander Christov                                           }
  132. { Notes    : Very instructive on the use of Pointers in TP.               }
  133. {            This version does not limit the number of elements to        }
  134. {            65535 since the need not be contiguous.                      }
  135. {                                                                         }
  136. {    Use freely.                                                          }
  137. {                                                                         }
  138. {─────────────────────────────────────────────────────────────────────────}
  139. Interface
  140.  
  141. Type CmpFunc=Function(El1,El2:Pointer):Boolean;
  142.      AddrFunc=Function(Base:Pointer;Size,N:LongInt):Pointer;
  143.      SwapProc=Procedure(El1,El2:Pointer;Size:LongInt);
  144.  
  145. Procedure QSort(Base:Pointer;      { Pointer to the first element.
  146.                                      if the user Writes his own GT, Addr and
  147.                                      Swap, this isn't Really necessary.
  148.                                    }
  149.                 Elements:LongInt;  { Total number of elements }
  150.                 Size:Word;         { Size of an element in Bytes }
  151.                 GT:CmpFunc;        { Comparing Function  }
  152.                 Addr:AddrFunc;     { Addressing Function }
  153.                 Swap:SwapProc);    { Swapping Function }
  154.  
  155. {
  156.   GT        - A funcion of Type CmpFunc that compares the elements pointed
  157.               to by its first and second arguments, and returns True if the
  158.               first element is Greater Than the second one. This Unit defines
  159.               some commonly used CmpFuncs:
  160.                     bGT - Compares Bytes
  161.                     wGT - Compares Words
  162.                     lGT - Compares LongInts
  163.                     rGT - Compares Reals
  164.  
  165.   Addr      - A Function that receives the index of an element and must
  166.               return a Pointer to it.
  167.               This Unit defines the Function
  168.                    LinearAddr
  169.               which can be used whenever the elements are located
  170.               contiguously in memory.
  171.  
  172.   Swap      - A Procedure that swaps the elements pointed by its arguments.
  173.                     DirectSwap
  174.               is defined in the Unit, which can be used whenever the elements
  175.               are mutually independent or no external processes are needed
  176.               when swapping two elements
  177. }
  178.  
  179. { Commonly used CmpFuncs }
  180.  
  181. Function bGT(El1,El2:Pointer):Boolean;      { Compares ^Byte }
  182. Function wGT(El1,El2:Pointer):Boolean;      { Compares ^Word }
  183. Function lGT(El1,El2:Pointer):Boolean;      { Compares ^LongInt }
  184. Function rGT(El1,El2:Pointer):Boolean;      { Compares ^Real }
  185.  
  186. Function LinearAddr(Base:Pointer;Size,N:LongInt):Pointer;
  187. Procedure DirectSwap(El1,El2:Pointer;Size:LongInt);
  188.  
  189. Implementation
  190. {$F+}
  191.  
  192. Type Dummy=Array[0..0] of Byte;
  193.      pDummy=^Dummy;
  194.  
  195.  
  196. Var X,Middle:Pointer;
  197.  
  198. Procedure
  199. _Sort(Base:Pointer;L,R:LongInt;Size:Word;GT:CmpFunc;Addr:AddrFunc;Swap:SwapProc
  200. );
  201. Var I,J:LongInt;
  202. begin
  203.  I:=L;
  204.  J:=R;
  205.  Move(Addr(Base,Size,(L+R) div 2)^,Middle^,Size);
  206.  Repeat
  207.   While GT(Middle,Addr(Base,Size,I)) do INC(I);
  208.   While GT(Addr(Base,Size,J),Middle) do DEC(J);
  209.   if I<=J then begin
  210.    if I<>J then Swap(Addr(Base,Size,I),Addr(Base,Size,J),Size);
  211.    INC(I);
  212.    DEC(J);
  213.   end;
  214.  Until I>J;
  215.  if L<J then _Sort(Base,L,J,Size,GT,Addr,Swap);
  216.  if I<R then _Sort(Base,I,R,Size,GT,Addr,Swap);
  217. end;
  218.  
  219. Procedure QSort;
  220. begin
  221.  GetMem(X,Size);  { <- Made in Arturo Ramirez 8-) }
  222.  GetMem(Middle,Size);
  223.  _Sort(Base,0,Elements-1,Size,GT,Addr,Swap);
  224.  FreeMem(X,Size);
  225.  FreeMem(Middle,Size);
  226. end;
  227.  
  228. Function bGT(El1,El2:Pointer):Boolean;
  229. Type pByte=^Byte;
  230. begin
  231.  bGt:=(pByte(El1)^>pByte(El2)^);
  232. end;
  233.  
  234. Function wGT(El1,El2:Pointer):Boolean;
  235. Type pWord=^Word;
  236. begin
  237.  wGt:=(pWord(El1)^>pWord(El2)^);
  238. end;
  239.  
  240. Function lGT(El1,El2:Pointer):Boolean;
  241. Type pLongInt=^LongInt;
  242. begin
  243.  lGt:=(pLongInt(El1)^>pLongInt(El2)^);
  244. end;
  245.  
  246. Function rGT(El1,El2:Pointer):Boolean;
  247. Type pReal=^Real;
  248. begin
  249.  rGt:=(pReal(El1)^>pReal(El2)^);
  250. end;
  251.  
  252. { Linear Addressing }
  253.  
  254. Function LinearAddr;
  255. begin
  256.  LinearAddr:=@pdummy(Base)^[N*Size];
  257. end;
  258.  
  259. { Direct swapping of elements. With the use of Addr() it is quite more
  260.  legible 8-) }
  261.  
  262. Procedure DirectSwap;
  263. Var Tmp:Pointer;
  264. begin
  265.  GetMem(Tmp,Size);
  266.  Move(El1^,Tmp^,Size);
  267.  Move(El2^,El1^,Size);
  268.  Move(Tmp^,El2^,Size);
  269.  FreeMem(Tmp,Size);
  270. end;
  271.  
  272. end.
  273.  
  274.  
  275. { And finally a specific version of QSort() written in Assembler. It is
  276.  non recursive and sorts Arrays of Words of up to 16383 elements (since
  277.  it Uses the addresses of the elements rather than their indexes, and since
  278.  SizeOf(Word)=2 -> 16384*2=32768 "=" -32768, and the routine Uses signed
  279.  comparisons between adresses.
  280.   On my 386/33 it sorts 10 times an Array of 10000 Words in 3.6 sec, While
  281.  the first QSort() does the same in 46 sec.
  282.  
  283.   Must be called With
  284.  
  285.  Qsort(Pointer to the first element, 0, elements-1)
  286.  
  287.   Use freely. if you include the source directly in your Program, credit
  288.   must be given.
  289. }
  290.  
  291. Procedure QSort(Base:Pointer;L,R:Word);Assembler;
  292. Var TmpL,TmpR,TmpDI:Word;
  293. Asm
  294.  xor AX,AX
  295.  PUSH AX
  296.  PUSH AX     { 0 0 will act as a flag on the stack indicating that no more }
  297.  PUSH R      { (L,R) pairs need to be sorted }
  298.  PUSH L
  299. @MainLoop:
  300.  LES DI,Base
  301.  MOV TmpDI,DI
  302.  xor SI,SI
  303.  MOV BX,DI
  304.  POP AX    { AX<-L }
  305.  MOV TmpL,AX
  306.  MOV SI,AX
  307.  SHL AX,1
  308.  ADD DI,AX
  309.  POP AX    { AX<-R }
  310.  MOV TmpR,AX
  311.  and AX,AX     { R can be never 0 except if this is the (0,0) flag }
  312.  JZ @end
  313.  ADD SI,AX
  314.  SHL AX,1
  315.  ADD BX,AX
  316.  and SI,$FFFE
  317.  ADD SI,TmpDI
  318.  
  319.  { ES:DI -> Element[I] (L)
  320.    ES:BX -> Element[J] (R)
  321.    ES:SI -> Element[(L+R) div 2]
  322.  }
  323.  
  324.  MOV AX,ES:[SI]
  325. @Loop1:
  326.  MOV CX,ES:[DI]
  327.  CMP AX,CX
  328.  JNA @Loop2
  329.  ADD DI,2
  330.  JMP @Loop1
  331. @Loop2:
  332.  MOV CX,ES:[BX]
  333.  CMP CX,AX
  334.  JNA @Check
  335.  SUB BX,2
  336.  JMP @Loop2
  337. @Check:
  338.  CMP DI,BX
  339.  JG @Cont1
  340.  MOV CX,ES:[DI]
  341.  MOV DX,ES:[BX]
  342.  MOV ES:[DI],DX
  343.  MOV ES:[BX],CX
  344.  ADD DI,2
  345.  SUB BX,2
  346.  CMP DI,BX
  347.  JNG @Loop1
  348.  
  349. @Cont1:
  350.  SUB DI,TmpDI
  351.  SAR DI,1       { DI - I }
  352.  SUB BX,TmpDI
  353.  SAR BX,1       { BX - J }
  354.  CMP DI,TmpR
  355.  JGE @Cont2
  356.  PUSH TmpR      { I<R }
  357.  PUSH DI
  358. @Cont2:
  359.  CMP TmpL,BX
  360.  JGE @MainLoop
  361.  PUSH BX        { L<J }
  362.  PUSH TmpL
  363.  JMP @MainLoop
  364.  
  365. @end:
  366. end;
  367.  
  368.